package com.hddz.acquisition;

import java.util.HashMap;

import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;

public class AppSetting {

	// These settings are stored in SharedPreferences
	private static String SHARED_PREFERENCES_NAME = "com.hddz.acquisition"; //$NON-NLS-1$

	// / Settings variables
	private Application ctx;
	private SharedPreferences globalPreferences;
	private SharedPreferences defaultProfilePreferences;
	private SharedPreferences profilePreferences;

	private static HashMap<String, String> globalConfig = new HashMap<String, String>();

	private static AppSetting INSTANCE;

	public static AppSetting getAppSetting(Context ctx) {
		if (INSTANCE == null) {
			synchronized (ctx.getApplicationContext()) {
				if (INSTANCE == null) {
					INSTANCE = new AppSetting(
							(Application) ctx.getApplicationContext());
				}
			}
		}
		return INSTANCE;
	}

	public interface OsmandPreference<T> {
		T get();

		boolean set(T obj);

		String getId();
	}

	private AppSetting(Application ctx) {
		this.ctx = ctx;
		profilePreferences = defaultProfilePreferences = globalPreferences = ctx
				.getSharedPreferences(SHARED_PREFERENCES_NAME,
						Context.MODE_PRIVATE);
	}

	public static String getConfigValue(String key) {
		synchronized (globalConfig) {
			if (globalConfig != null && globalConfig.containsKey(key)) {
				return globalConfig.get(key);
			} else {
				return key;
			}
		}
	}

	public static boolean findConfigValue(String key) {
		synchronized (globalConfig) {
			if (globalConfig != null && globalConfig.containsKey(key)) {
				return true;
			} else {
				return false;
			}
		}
	}

	public static void putConfigValue(String key, String value) {
		synchronized (globalConfig) {
			if (!globalConfig.containsKey(key)) {
				globalConfig.put(key, value);
			} else {
				globalConfig.remove(key);
				globalConfig.put(key, value);
			}
		}
	}

	private SharedPreferences getProfilePreferences() {
		return ctx.getSharedPreferences(SHARED_PREFERENCES_NAME,
				Context.MODE_WORLD_READABLE);
	}

	public abstract class CommonPreference<T> implements OsmandPreference<T> {
		private final String id;
		private final boolean global;
		private T cachedValue;
		private SharedPreferences cachedPreference;
		private boolean cache;
		private T defaultValue;

		public CommonPreference(String id, boolean global, T defaultValue) {
			this.id = id;
			this.global = global;
			this.defaultValue = defaultValue;
		}

		public CommonPreference(String id, boolean global, boolean cache,
				T defaultValue) {
			this.id = id;
			this.global = global;
			this.cache = cache;
			this.defaultValue = defaultValue;
		}

		protected SharedPreferences getPreferences() {
			return global ? globalPreferences : profilePreferences;
		}

		protected T getDefaultValue() {
			if (global) {
				return defaultValue;
			}
			if (defaultProfilePreferences.contains(getId())) {
				return getValue(defaultProfilePreferences, defaultValue);
			} else {
				return defaultValue;
			}
		}

		protected abstract T getValue(SharedPreferences prefs, T defaultValue);

		protected abstract boolean setValue(SharedPreferences prefs, T val);

		@Override
		public T get() {
			if (cache && cachedValue != null
					&& cachedPreference == getPreferences()) {
				return cachedValue;
			}
			cachedPreference = getPreferences();
			cachedValue = getValue(cachedPreference, getDefaultValue());
			return cachedValue;
		}

		@Override
		public String getId() {
			return id;
		}

		@Override
		public boolean set(T obj) {
			SharedPreferences prefs = getPreferences();
			if (setValue(prefs, obj)) {
				cachedValue = obj;
				cachedPreference = prefs;
				return true;
			}
			return false;
		}

	}

	private class BooleanPreference extends CommonPreference<Boolean> {

		private BooleanPreference(String id, boolean defaultValue,
				boolean global) {
			super(id, global, defaultValue);
		}

		private BooleanPreference(String id, boolean defaultValue,
				boolean global, boolean cache) {
			super(id, global, cache);
		}

		@Override
		protected Boolean getValue(SharedPreferences prefs, Boolean defaultValue) {
			return prefs.getBoolean(getId(), defaultValue);
		}

		@Override
		protected boolean setValue(SharedPreferences prefs, Boolean val) {
			return prefs.edit().putBoolean(getId(), val).commit();
		}

	}

	private class IntPreference extends CommonPreference<Integer> {

		private IntPreference(String id, int defaultValue, boolean global) {
			super(id, global, defaultValue);
		}

		private IntPreference(String id, int defaultValue, boolean global,
				boolean cache) {
			super(id, global, cache, defaultValue);
		}

		@Override
		protected Integer getValue(SharedPreferences prefs, Integer defaultValue) {
			return prefs.getInt(getId(), defaultValue);
		}

		@Override
		protected boolean setValue(SharedPreferences prefs, Integer val) {
			return prefs.edit().putInt(getId(), val).commit();
		}

	}

	private class LongPreference extends CommonPreference<Long> {

		private LongPreference(String id, Long defaultValue, boolean global) {
			super(id, global, defaultValue);
		}

		private LongPreference(String id, Long defaultValue, boolean global,
				boolean cache) {
			super(id, global, cache, defaultValue);
		}

		@Override
		protected Long getValue(SharedPreferences prefs, Long defaultValue) {
			return prefs.getLong(getId(), defaultValue);
		}

		@Override
		protected boolean setValue(SharedPreferences prefs, Long val) {
			return prefs.edit().putLong(getId(), val).commit();
		}

	}

	private class StringPreference extends CommonPreference<String> {

		private StringPreference(String id, String defaultValue, boolean global) {
			super(id, global, defaultValue);
		}

		@Override
		protected String getValue(SharedPreferences prefs, String defaultValue) {
			return prefs.getString(getId(), defaultValue);
		}

		@Override
		protected boolean setValue(SharedPreferences prefs, String val) {
			return prefs.edit().putString(getId(), val).commit();
		}

	}

	private class EnumIntPreference<E extends Enum<E>> extends
			CommonPreference<E> {

		private final E[] values;

		private EnumIntPreference(String id, E defaultValue, boolean global,
				boolean cache, E[] values) {
			super(id, global, cache, defaultValue);
			this.values = values;
		}

		private EnumIntPreference(String id, E defaultValue, boolean global,
				E[] values) {
			super(id, global, defaultValue);
			this.values = values;
		}

		@Override
		protected E getValue(SharedPreferences prefs, E defaultValue) {
			int i = prefs.getInt(getId(), -1);
			if (i < 0 || i >= values.length) {
				return defaultValue;
			}
			return values[i];
		}

		@Override
		protected boolean setValue(SharedPreferences prefs, E val) {
			return prefs.edit().putInt(getId(), val.ordinal()).commit();
		}

	}

	public CommonPreference<Boolean> BLUETOOTH_DEVICE_STATE = new BooleanPreference(
			"bluetooth_device_state", false, true);
	public CommonPreference<String> BLUETOOTH_DEVICE_ADDRESS = new StringPreference(
			"bluetooth_device_address", "", true);
	public CommonPreference<String> USER_CODE = new StringPreference(
			"user_code", "", true);

	public CommonPreference<String> UC = new StringPreference("uc", "", true);
	public CommonPreference<String> UN = new StringPreference("un", GlobalConst.getPhoneSign(), true);
	public CommonPreference<String> UPWD = new StringPreference("upwd", "",
			true);
	public CommonPreference<Boolean> AUTO_LOGIN = new BooleanPreference(
			"auto_login", false, true);

	public CommonPreference<Long> LAST_LOGIN = new LongPreference("last_login",
			0L, true);

	public CommonPreference<String> SERVER_ADDRESS = new StringPreference(
			"server_address", "114.215.210.209:8833", true);

	public CommonPreference<String> CODE_MODE = new StringPreference(
			"code_mode", "6,16", true);

	// public CommonPreference<String> VOUCH_TYPE = new StringPreference(
	// "vouch_type", "59", true);
	public CommonPreference<String> VOUCH_TYPE = new StringPreference(
			"vouch_type", "07", true);

	// public CommonPreference<String> IMPORT_TYPE = new StringPreference(
	// "import_type", "14", true);

	public CommonPreference<String> IMPORT_TYPE = new StringPreference(
			"import_type", "01", true);


	public CommonPreference<Boolean> IS_FIRST = new BooleanPreference(
			"is_first", true, true);

	public static int[] codeMode = new int[] { 6, 16 };
}
